package 面向对象;
/**
 多态:对象在运行过程中不同的形态
 分类:1，方法的重载和重写 2，对象的多态性
 对象的多态性:
   对象的多态性是由继承关系中多个类而来，
   向上转型:将子类实例转为父类引用
     >格式: 父类 父类对象=子类实例         自动转换
	 >以基本数据类型为例   int i='a'(char的容量比int小，可以自动完成)
   向下转型:将父类实例转化为子类实例
     >格式: 子类 子类对象=(子类) 父类对象   强制转换
	 >以基本数据类型为例   char c=(char)97 (int 4字节 char 2字节  需强制转型)
  多态小结：
    1，方法的重载和重写就是方法的多态性
	2，多个子类就是父类的多种形态
	3，父类引用可以指向子类对象，自动转换
	4，子类对象指向父类引用需强制转换，类型不对会报异常
	5，实际开发中尽量利用父类引用，即第三种，向上转型，利于扩展
 */
 /**
   instanceof用法:
       用于检查对象是否为指定的类型，通常用在把父类引用强制转换为子类引用时,
	   以避免出现类型转换异常(ClassCastException)
   语法： 对象 instanceof 类型  返回 布尔值 true/false
   if( 对象1 instanceof 类1){} 判断对象是否是类的实例
 */
 /**
   instanceof 如果父类的子类过多，判断有些繁琐
   父类设计法则:
      1，父类通常设计为抽象类和接口，优先接口，接口不能满足再设计抽象类
	  2，尽可能避免具体了继承具体类，好处是无需检查对象是否为父类的对象
 */
public class 多态instanceof
{
	public static void main(String[] args)
	{
		//HomeDog hd=new HomeDog("阿黄");
		//hd.eat();
		//PetDog pd=new PetDog("蛋黄");
		//pd.eat();
		//hd=pd;  编译期错误，类型不一致
		//对象的多态性
		Dog hd=new HomeDog("阿黄");//用父类的引用指向子类对象(大的接收小的)，向上转型(自动转换)
		Dog pd=new PetDog("蛋黄");
		hd.eat();
		pd.eat();
		//hd=pd;
		//hd.eat();//可正常编译运行
		
		Dog td=new ToyDog("小度");//新添加的玩具狗依然可以用eat(td)方法
		eat(td);
		//eat(hd);//编译期正常，运行期会抛异常，homedog不能转换为toydog
		eat(hd);//添加instanceof判断后，运行正常
		
	}
	//抽象(粒度)，面向抽象编程,优点:未来有新的dog类型，此方法依然可重复用
	public static void eat(Dog d)
	{
		System.out.println("狗吃饭");
		d.eat();
		//d.skill();这样写，会编译器错误，因为编译时大类d里没有skill方法，需要强制转换
		//强制转换，当然需要传进来的d为toydog类，不然报错
		//ToyDog ttd=(ToyDog) d;//父类转换为子类，向下转型(强制转换)
		//ttd.skill();
		//为了避免父类实例强制转换为子类实例时的类型转换异常，
		//转换前对类型进行检测(判断)
		if (d instanceof ToyDog){
			ToyDog td=(ToyDog)d;
			td.skill();
		}
	}
}


abstract class Dog
{
	private String name;

	public Dog(String name)
	{
		this.name = name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public abstract void eat();
}

class HomeDog extends Dog
{
	public HomeDog(String name)
	{
		super(name);
	}

	@Override
	public void eat()
	{
		System.out.println("我是家狗,名字是:" + super.getName() + ",我吃剩饭");
	}	
}
class PetDog extends Dog
{
	public PetDog(String name)
	{
		super(name);
	}

	@Override
	public void eat()
	{
		System.out.println("我是宠物狗,名字是:" + super.getName() + ",我吃狗粮");
	}
}
class ToyDog extends Dog{
	public ToyDog(String name){
		super(name);
	}

	@Override
	public void eat()
	{
		System.out.println("我是玩具狗，名字是:"+super.getName()+",我不吃饭");
	}

	public void skill(){
		System.out.println("我是玩具狗，我会唱歌、跳舞、讲故事");
	}
}
